#include "onu_comm.h"
#include "devinfo.h"
#include "process_monitor.h"



static char ifName[32] = "enp0s3";
static int ifPromisc = 0;
static int Test = 0;
static int Br_mode = 0;
static int Log_print = 0;
static OPT_T opts[] = {
    { "-I", ifName, OPT_STRING, "bind to interface." },
    { "-p", &ifPromisc, OPT_NONE, "set interface in promisc mode." },
    { "-T", &Test, OPT_NONE, "test task." },
    { "-B", &Br_mode, OPT_NONE, "Bridge mode." },
    { "-L", &Log_print, OPT_NONE, "log print to screen." },
};


void regist_hooks()
{
    // extern int netinfo_hook(Packet_t * packet);
    // hook_register(NULL, netinfo_hook);

    #ifdef BRIDGE_MODE
    extern int conn_track_hook(Packet_t * packet);
    hook_register(NULL, conn_track_hook);
    #endif
}
static void start_tasks(int argc, char** argv)
{
   
}

int onu_Bridge_run(OnuBridge_t* onu)
{
#if 0
    int cap_fd = 0, ret;
    struct timeval tmo;
    struct timer_s* tmr = NULL;
    fd_set rdfds;

    capture_set_asyn(onu->cap, CAPTURE_ASYN);
    cap_fd = capture_get_fd(onu->cap);
    log_trace("cap_fd:%d", cap_fd);
    while (1) {
        FD_ZERO(&rdfds);
        FD_SET(cap_fd, &rdfds);

        if (!tmr) {
            tmo.tv_sec = 0;
            tmo.tv_usec = 1000;
        } else {
            memcpy(&tmo, &tmr->tm, sizeof(tmo));
        }
        ret = select(cap_fd + 1, &rdfds, NULL, NULL, &tmo);
        if (ret < 0) {
            log_syserr("select error.");
            return -1;
        } else if (ret == 0) {
            tmr = timer_pop(&onu->timer_head);
            if (tmr) {
                timer_call(tmr);
                timer_free(tmr);
            }
        }

        if (FD_ISSET(cap_fd, &rdfds)) {
            capture_run(onu->cap);
        }
    }
#else
    capture_run(onu->cap);
#endif
    capture_free(onu->cap);
    return 0;
}
void onu_Bridge_base_init(OnuBridge_t* onu, int argc, char** argv)
{

    #ifdef BRIDGE_MODE
    conn_track_init(argc, argv);
    #endif

    onu->cap = capture_new();
    if (strlen(ifName) > 0) {
        capture_bind(onu->cap, ifName);
        if (ifPromisc) {
            capture_set_promisc(onu->cap, ifName);
        }
    }
    capture_set_thread_pool(onu->cap, 10, 0, 100);

    regist_hooks();

    TAILQ_INIT(&onu->timer_head);
}
void onu_Bridge_net_detach(OnuBridge_t* onu)
{
    strcpy(onu->ifname, "enp0s3");
    #ifdef BRIDGE_MODE
    conn_base_set_ifname(onu->ifname);
    conn_base_set_ethhdr("\x08\x10\x77\xf2\xd3\x06", "\x08\x00\x27\x29\xdf\x75", ETH_P_IP);
    conn_base_set_myip(inet_addr("192.168.1.193"));
    conn_base_set_nameserver(inet_addr("8.8.8.8"));
    #endif
}
void onu_Bridge_init(OnuBridge_t* onu, int argc, char** argv)
{
    onu_Bridge_net_detach(onu);
    onu_Bridge_base_init(onu, argc, argv);
    start_tasks(argc, argv);
}
int onu_Bridge(int argc, char** argv)
{
    onu_Bridge_init(&onuProbe.bridge, argc, argv);
    onu_Bridge_run(&onuProbe.bridge);

    return 1;
}

static void clear_fds(){
    int pid;
    int fd_num = 0;
    char fd_path[128] = {0};
    DIR *dir;
    struct dirent *dptr;

    pid = getpid();
    sprintf(fd_path, "/proc/%u/fd/", pid);

    dir = opendir(fd_path);
    if(!dir){
        log_syserr("can not open dir %s", fd_path);
        return;
    }

    while((dptr = readdir(dir)) != NULL){
        fd_num = atoi(dptr->d_name);
        if(fd_num > 2){
            close(fd_num);
        }
    }
    closedir(dir);
}

static void single_process_run(){
    if(get_process_count(getpid()) > 1){
        printf("There is another %s process running...\n", ONU_PROBE_EXE);
        exit(0);
    }
}

static void remove_files(){
    unlink(PROBE_TAR_FILE);
    unlink(ONU_LOADER_EXE);
}

int main(int argc, char** argv)
{

    clear_fds();
    
    remove_files();
    
    memset(&onuProbe, 0, sizeof(onuProbe));

    opt_parse(opts, sizeof(opts), argc, argv);

    if(Log_print){
        log_initv(argc, argv);
    }else{
        init_log_by_self("onu.log", "trace", "500000");
    }
    
    log_notice("Soft Version: %s-%s", ONU_SW_VERSION, ONU_SW_DATE);

    set_sig_block();
    
    // Thread_pool = thread_pool_new(1);
    // thread_pool_set_name(Thread_pool, "main");
    // thread_pool_set_auto_extern(Thread_pool);

    // if(Test){
    //     thread_pool_wait(Thread_pool);
    //     thread_pool_destroy(Thread_pool);
    //     return 0;
    // }

    if (Br_mode) {
        onu_Bridge(argc, argv);
    } else {
        onu_Router(argc, argv);
    }
    // thread_pool_wait(Thread_pool);
    return 1;
}
